package com.feifan.utils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import com.feifan.annotation.MyAutowired;
import com.feifan.annotation.MyController;
import com.feifan.annotation.MyRequestMapping;
import com.feifan.annotation.MyService;
import com.feifan.annotation.PackageScann;

public class IOCUtils {

    private IOCUtils() {}

    private static HashMap<String, Object> beanMaps = new HashMap<>();

    private static HashMap<String, Class<?>> classMaps = new HashMap<>();

    private static HashMap<String, Method> urlMaps = new HashMap<>();

    private static String basePackage = null;

    private static Class<?> clazz = null;

    public static HashMap<String, Object> getBeanMaps() {
        return beanMaps;
    }

    public static HashMap<String, Method> getUrlMaps() {
        return urlMaps;
    }

    public static HashMap<String, Class<?>> getClassMaps() {
        return classMaps;
    }

    /**
     * 获取扫描的包名。默认为dispather所在的包名
     * 
     * @return
     * @throws IOException
     */
    public static void getBasePackage(Class<?> clazz) {
        IOCUtils.clazz = clazz;
        PackageScann annotation = clazz.getAnnotation(PackageScann.class);
        if (annotation == null) {
            return;
        }
        String className = clazz.getTypeName();
        basePackage =
            "".equals(annotation.value()) ? className.substring(0, className.lastIndexOf(".")) : annotation.value();
        // 获取指定包下面的所有的class 文件
        getClassFiles();
    }

    /**
     * 获取包名及其子包下面的所有的class文件
     */
    private static void getClassFiles() {
        // 将com.feifan 转换成文件夹形式com/feifan 再类加载读取文件
        String fileString = basePackage.replaceAll("\\.", "/");
        // 得到com/feifan的绝对地址 、D:xxx/com/feifan
        String rootPath = clazz.getClassLoader().getResource(fileString).getPath();
        // 直留着com/feifan,拼接类全名
        if (rootPath != null)
            rootPath = rootPath.substring(rootPath.indexOf(fileString));
        try {
            Enumeration<URL> enumeration = clazz.getClassLoader().getResources(fileString);
            while (enumeration.hasMoreElements()) {
                URL url = (URL)enumeration.nextElement();
                if (url.getProtocol().equals("file")) {
                    // 如果是文件
                    File file = new File(url.getPath().substring(1));
                    Scanner(file, rootPath);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 封装类名，字节码 classMaps
     * 
     * @param file
     * @param rootPath
     */
    private static void Scanner(File file, String rootPath) {
        File[] files = file.listFiles();
        for (int i = 0; files != null && i < files.length; i++) {
            File file2 = files[i];
            if (file2.isDirectory()) {
                Scanner(file2, rootPath + file2.getName() + "/");
            } else {
                if (file2.getName().endsWith(".class")) {
                    String classname = (rootPath + file2.getName()).replaceAll("/", ".");
                    // 去掉.class 后缀字节码存入
                    classname = classname.substring(0, classname.lastIndexOf("."));
                    try {
                        classMaps.put(classname, Class.forName(classname));
                    } catch (ClassNotFoundException e) {
                        // TODO 获取字节码文件异常
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 生成自定义注解注解的bean
     */
    public static void createBeanMaps() {
        if (classMaps == null) {
            return;
        }
        Class<?> clazz = null;
        String pathRoot = "";
        String path = "";
        String beanKey = "";
        for (Map.Entry<String, Class<?>> entry : classMaps.entrySet()) {
            clazz = entry.getValue();
            // 控制层注解
            if (clazz.isAnnotationPresent(MyController.class)) {
                if (clazz.isAnnotationPresent(MyRequestMapping.class)) {
                    pathRoot = clazz.getAnnotation(MyRequestMapping.class).value();
                    if (!pathRoot.startsWith("/")) {
                        pathRoot = "/" + pathRoot;
                    }
                    if (!pathRoot.endsWith("/")) {
                        pathRoot = pathRoot + "/";
                    }
                }
                // url 映射路径
                Method[] methods = clazz.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(MyRequestMapping.class)) {
                        path = method.getAnnotation(MyRequestMapping.class).value();
                        if (path.startsWith("/")) {
                            if (path.length() > 1) {
                                path = path.substring(path.indexOf("/") + 1);
                            } else {
                                path = "";
                            }
                        }
                        urlMaps.put(pathRoot + path, method);
                    }
                }

                beanKey = clazz.getSimpleName();
                beanKey = beanKey.substring(0, 1).toLowerCase() + beanKey.substring(1);
                try {
                    beanMaps.put(beanKey, clazz.newInstance());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            // 服务层注解
            if (clazz.isAnnotationPresent(MyService.class)) {

                Class<?>[] classes = clazz.getInterfaces();
                try {
                    for (Class<?> class1 : classes) {
                        beanKey = class1.getSimpleName();
                        beanKey = beanKey.substring(0, 1).toLowerCase() + beanKey.substring(1);
                        beanMaps.put(beanKey, clazz.newInstance());
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }

            }
        }

        createAutowried();
    }

    /**
     * 自动注入参数
     */
    private static void createAutowried() {

        if (classMaps == null) {
            return;
        }

        Class<?> clazz = null;
        String parm = "";
        String beanName = "";
        for (Map.Entry<String, Class<?>> entry : classMaps.entrySet()) {
            clazz = entry.getValue();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(MyAutowired.class)) {
                    parm = field.getType().toString();
                    parm = parm.substring(parm.lastIndexOf(".") + 1);
                    parm = parm.substring(0, 1).toLowerCase() + parm.substring(1);

                    beanName = clazz.getSimpleName();
                    beanName = beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
                    try {
                        field.setAccessible(true);
                        field.set(beanMaps.get(beanName), beanMaps.get(parm));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 获取当前方法的主类
     * 
     * @param method
     * @return
     */
    public static Object newInstance(Method method) {
        String simpleName = method.getDeclaringClass().getSimpleName();
        simpleName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
        return beanMaps.get(simpleName);
    }
}
